{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Week 1 Day 2 - Webpage Summarizer using Ollama (llama3.2)\n",
        "\n",
        "This notebook upgrades the Day 1 project to use an open-source local model via Ollama instead of OpenAI.\n",
        "\n",
        "- Model: `llama3.2` (or `llama3.2:1b` if your machine is slower)\n",
        "- Endpoint: `http://localhost:11434/v1` (OpenAI-compatible)\n",
        "- No API charges; data stays on your machine\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Client ready. Using model: llama3.2\n"
          ]
        }
      ],
      "source": [
        "# Setup Ollama OpenAI-compatible client\n",
        "import os\n",
        "from openai import OpenAI\n",
        "from dotenv import load_dotenv\n",
        "\n",
        "# Optional .env for other configs\n",
        "load_dotenv(override=True)\n",
        "\n",
        "OLLAMA_BASE_URL = \"http://localhost:11434/v1\"\n",
        "MODEL = os.getenv(\"OLLAMA_MODEL\", \"llama3.2\")  \n",
        "\n",
        "# Create client pointing to Ollama endpoint (api_key can be any non-empty string)\n",
        "ollama = OpenAI(base_url=OLLAMA_BASE_URL, api_key=\"ollama\")\n",
        "\n",
        "print(f\"Client ready. Using model: {MODEL}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Scraper ready.\n"
          ]
        }
      ],
      "source": [
        "# Minimal scraper utilities (requests + BeautifulSoup)\n",
        "import requests\n",
        "from bs4 import BeautifulSoup\n",
        "from urllib.parse import urljoin\n",
        "\n",
        "HEADERS = {\n",
        "    \"User-Agent\": (\n",
        "        \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) \"\n",
        "        \"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\"\n",
        "    )\n",
        "}\n",
        "\n",
        "def fetch_website_contents(url, char_limit=2000):\n",
        "    try:\n",
        "        r = requests.get(url, headers=HEADERS, timeout=15)\n",
        "        r.raise_for_status()\n",
        "        html = r.text\n",
        "    except Exception as e:\n",
        "        return f\"Error fetching {url}: {e}\"\n",
        "\n",
        "    soup = BeautifulSoup(html, \"html.parser\")\n",
        "\n",
        "    # Remove scripts/styles\n",
        "    for el in soup([\"script\", \"style\", \"noscript\", \"template\"]):\n",
        "        el.decompose()\n",
        "\n",
        "    title = soup.title.get_text(strip=True) if soup.title else \"No title\"\n",
        "    text = soup.get_text(\"\\n\")\n",
        "    # Basic whitespace cleanup\n",
        "    lines = [ln.strip() for ln in text.splitlines() if ln.strip()]\n",
        "    text = \"\\n\".join(lines)\n",
        "\n",
        "    return (f\"{title}\\n\\n{text}\")[:char_limit]\n",
        "\n",
        "print(\"Scraper ready.\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Summarizer ready.\n"
          ]
        }
      ],
      "source": [
        "# Summarization with llama3.2 via Ollama's OpenAI-compatible API\n",
        "from IPython.display import Markdown, display\n",
        "\n",
        "def summarize_url(url, model=MODEL, temperature=0.4, max_tokens=400):\n",
        "    website = fetch_website_contents(url, char_limit=3000)\n",
        "\n",
        "    system_prompt = (\n",
        "        \"You are a helpful assistant that analyzes a website's textual content \"\n",
        "        \"and produces a clear, concise markdown summary with bullet points.\"\n",
        "    )\n",
        "\n",
        "    user_prompt = f\"\"\"\n",
        "Here are the contents of a website.\n",
        "Provide a short summary of this website in markdown.\n",
        "Include key sections, offerings, and any notable announcements.\n",
        "\n",
        "{website}\n",
        "\"\"\"\n",
        "\n",
        "    resp = ollama.chat.completions.create(\n",
        "        model=model,\n",
        "        messages=[\n",
        "            {\"role\": \"system\", \"content\": system_prompt},\n",
        "            {\"role\": \"user\", \"content\": user_prompt},\n",
        "        ],\n",
        "        temperature=temperature,\n",
        "        max_tokens=max_tokens,\n",
        "    )\n",
        "\n",
        "    return resp.choices[0].message.content\n",
        "\n",
        "\n",
        "def display_summary(url, **kwargs):\n",
        "    print(f\"Summarizing with {MODEL} @ Ollama → {url}\")\n",
        "    md = summarize_url(url, **kwargs)\n",
        "    display(Markdown(md))\n",
        "\n",
        "print(\"Summarizer ready.\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Summarizing with llama3.2 @ Ollama → https://the-star.co.ke\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "**The Star Website Summary**\n",
              "=====================================\n",
              "\n",
              "### Key Sections\n",
              "\n",
              "*   **News**: Latest news articles, including updates on Mashujaa Day celebrations, politics, business, health, and more.\n",
              "*   **Podcasts**: Audio content available for listening or download.\n",
              "*   **In-pictures**: Galleries of photos related to various topics.\n",
              "\n",
              "### Offerings\n",
              "\n",
              "*   **Mashujaa Day Coverage**: In-depth coverage of the Kenya's Mashujaa Day celebrations, including news articles, performances, and events.\n",
              "*   **Raila Odinga Tribute**: Articles and features honoring the late former President Raila Odinga, including his life, legacy, and impact on Kenyan politics.\n",
              "\n",
              "### Notable Announcements\n",
              "\n",
              "*   **KQ-Qatar Airways Deal**: Partnership to open travel to 19 destinations, effective October 26, 2025.\n",
              "*   **Raila's State Burial**: Details of the state funeral ceremony held for former President Raila Odinga.\n",
              "*   **Mashujaa Day Performances**: Special performances honoring Raila Odinga, including music and cultural events.\n",
              "\n",
              "### Other Key Content\n",
              "\n",
              "*   **Editorials and Op-Eds**: Articles on current events, politics, and social issues from various perspectives.\n",
              "*   **Infographics**: Visual representations of data and information on topics such as Kenyan leaders who have been accorded state funeral, phrases Raila Odinga loved, and more."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Try it out\n",
        "TEST_URL = \"https://the-star.co.ke\"  # change to any site you want\n",
        "\n",
        "display_summary(TEST_URL, temperature=0.4, max_tokens=400)\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".venv",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.12"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
